use std::{collections::HashMap, error::Error};
use rand::Rng;
use regex::Regex;

use crate::{channel::{tcp::prelude::NrWriter, cmd::Data, http}, cli::conf::ConfCliPlus};

use super::func::{Function, ReqFunction, UserFunction, ResFunction, CliFunction};

use crate::channel::http::prelude::{ NrReq };

/// 保存核心集合
pub struct Keeper {
    // 终端CID | (终端配置/写出流)
    cli: HashMap<i64, (ConfCliPlus, NrWriter)>,
    // 匹配规则 | 终端CID列表
    rule: HashMap<String, Vec<i64>>,
    // 用户UID | 写出流
    user: HashMap<i64, NrWriter>,
    // 请求RID | (对应的用户端UID, 是否保持连接)
    req: HashMap<i64, (i64, bool)>,
}

impl Keeper {
    
    pub fn init() -> Self {
        Self { cli: HashMap::new(), rule: HashMap::new(), user: HashMap::new(), req: HashMap::new() }
    }

    pub fn func_handle(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        match func.kind() {
            super::func::FunctionType::UpdateCli => {
                self.update_cli(func)
            },
            super::func::FunctionType::RemoveCli => {
                self.remove_cli(func)
            },
            super::func::FunctionType::UpdateUser => {
                self.update_user(func)
            },
            super::func::FunctionType::RemoveUser => {
                self.remove_user(func)
            },
            super::func::FunctionType::UpdateReq => {
                self.update_req(func)
            },
            super::func::FunctionType::CliRes => {
                self.cli_res(func)
            },
        }
    }

    fn update_cli(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let cli_func = match func.as_any().downcast_ref::<CliFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        let mut conf_change = false;
        match self.cli.get_mut(&cli_func.cid) {
            Some((conf, stream)) => {
                if cli_func.conf.is_some() {
                    conf_change = true;
                    *conf = cli_func.conf.clone().unwrap();
                }
                if cli_func.stream.is_some() {
                    *stream = cli_func.stream.clone().unwrap();
                }
            },
            None => {
                conf_change = true;
                self.cli.insert(cli_func.cid, (cli_func.conf.clone().unwrap(), cli_func.stream.clone().unwrap()));
            },
        }
        if conf_change {
            self.update_rule(&cli_func.cid);
        }
        Ok(())
    }

    fn remove_cli(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let cli_func = match func.as_any().downcast_ref::<CliFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        self.cli.remove(&cli_func.cid);
        self.clear_rule(&cli_func.cid);
        Ok(())
    }

    fn update_rule(&mut self, cid: &i64) {
        self.clear_rule(cid);
        let (conf, _) = self.cli.get_mut(cid).unwrap();
        for rule in conf.cli.rule.clone() {
            match self.rule.get_mut(&rule) {
                Some(cids) => {
                    if !cids.contains(&cid) {
                        cids.push(*cid);
                    }
                },
                None => {
                    let mut temp = vec![];
                    temp.push(*cid);
                    self.rule.insert(rule.clone(), temp);
                },
            }
        }
    }

    fn clear_rule(&mut self, cid: &i64) {
        for (_, cids) in self.rule.iter_mut() {
            for (index, tid) in cids.iter_mut().enumerate() {
                if tid == cid {
                    cids.remove(index);
                    break;
                }
            }
        }
    }

    fn update_user(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let user_func = match func.as_any().downcast_ref::<UserFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        self.user.insert(user_func.uid, user_func.stream.clone().unwrap());
        Ok(())
    }

    fn remove_user(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let user_func = match func.as_any().downcast_ref::<UserFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        self.user.remove(&user_func.uid);
        Ok(())
    }

    fn update_req(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let req_func = match func.as_any().downcast_ref::<ReqFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        self.req.insert(req_func.pid, (req_func.uid.unwrap(), req_func.req.as_ref().unwrap().keep_alive()));
        match self.match_route(req_func.req.as_ref().unwrap()) {
            Some(cid) => {
                match self.cli.get_mut(&cid) {
                    Some((_, w)) => {
                        w.write(&Data::proxy_cli(req_func.req.as_ref().unwrap().to_vec(), 0_i64, req_func.pid).to_vec()).unwrap();
                    },
                    None => return Err(format!("Can't find cli stream of cid: {}", &cid).into()),
                }
            },
            None => {
                self.req.remove(&req_func.pid);
                match self.user.get_mut(req_func.uid.as_ref().unwrap()) {
                    Some(w) => {
                        w.write(&http::prelude::status_404().as_bytes().to_vec()).unwrap();
                    },
                    None => return Err(format!("Can't find user stream of uid: {}", req_func.uid.as_ref().unwrap()).into()),
                }
            },
        }
        Ok(())
    }

    fn match_route(&self, req: &NrReq) -> Option<i64> {
        let uri = &req.uri;
        let mut bp = Option::None;
        for ( route, clis ) in self.rule.iter() {
            if ".*".eq(route) {
                continue;
            }
            let reg = Regex::new(route).unwrap();
            if reg.is_match(uri) {
                bp = Option::Some(clis);
                break;
            }
        }
        if bp.is_some() && bp.unwrap().len() > 0 {
            let index = bp.unwrap().get(rand::thread_rng().gen_range(0..bp.unwrap().len())).unwrap();
            return Option::Some(*index);
        } else {
            let all_match = self.rule.get(".*");
            if all_match.is_some() && all_match.unwrap().len() > 0 {
                let index = all_match.unwrap().get(rand::thread_rng().gen_range(0..all_match.unwrap().len())).unwrap();
                return Option::Some(*index);
            }
        }
        Option::None
    }

    fn cli_res(&mut self, func: Box<dyn Function>) -> Result<(), Box<dyn Error>> {
        let res_func = match func.as_any().downcast_ref::<ResFunction>() {
            Some(f) => f,
            None => return Err("Parse type error".into()),
        };
        match self.req.get(&res_func.pid) {
            Some((uid, keep_alive)) => {
                match self.user.get_mut(uid) {
                    Some(w) => {
                        w.write(&res_func.data).unwrap();
                    },
                    None => {
                        println!("===> Lose user stream");
                    },
                }
                if !keep_alive {
                    self.user.remove(uid);
                }
            },
            None => {
                println!("===> Lose pid");
            },
        }
        self.req.remove(&res_func.pid);
        Ok(())
    }

}
